﻿    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Media;

    public enum direction { up, down, left, right,forward,backward,other };
    public class collosininfo
    {
        public collosininfo(direction d, float i)
        {
            direction = d;
            intersection = i;
        }
        public direction direction;
        public float intersection;
    }

    public class Movable
    {
        public Vector3 OldPosition = new Vector3(0, 0, 0);
        public Vector3 Position;
        public Vector3 Vellasity = new Vector3(0, 0, 0);
        protected Vector3 Acceleration = new Vector3(0, 0, 0);
        public Vector3 Orientation;
        protected Vector3 AngularVelocity = new Vector3(0, 0, 0);
        protected Vector3 Torque = new Vector3(0, 0, 0);
        protected Vector3 Force = new Vector3(0, 0, 0);
        protected float Mass = 1;
        protected float Drag = 0.999f;
        protected float momentOfInertia = 0.95f;
        protected float elasticity = -0.2f;
        protected Vector3 size = new Vector3(10f, 90f, 10f);

        protected bool contact = false;

        VertexPositionColor[] vertices;
        int[] indices;
        


        protected void Move(float dtm){
            float dt = dtm / 1000;
            OldPosition = Position;
            Position += Vellasity * dt;

            if (contact)
            {
                Vellasity *= 0.9f;
            }

            Matrix rotationMatrix = Matrix.CreateRotationY(-Orientation.Y);// *
            //Matrix.CreateRotationX(Orientation.X);
            Acceleration = Vector3.Transform(Force, rotationMatrix);

            Vellasity += Acceleration * dt;
            Vellasity *=Drag;

            
            Force = Vector3.Zero;
            Force += Vector3.Down * 1000;//garvitation
            Orientation += AngularVelocity * dt;
            AngularVelocity += Torque * dt;
            AngularVelocity *= momentOfInertia;
            Torque = Vector3.Zero;
        }

        public virtual BoundingBox getAABB()
        {
            Vector3[] buildingPoints = new Vector3[2];
            buildingPoints[0] = (new Vector3(size.X * -0.5f, size.Y * -0.5f, size.Z * -0.5f)) + Position ;
            buildingPoints[1] = (new Vector3(size.X * 0.5f, size.Y * 0.5f, size.Z * 0.5f)) + Position ;
            
            return BoundingBox.CreateFromPoints(buildingPoints);
            
        }

        private void SetUpVertices(BoundingBox box)
        {
            

            Vector3 max = box.Max;
            Vector3 min = box.Min;
            vertices = new VertexPositionColor[8];


            vertices[0].Position = min;
            vertices[0].Color = Color.Red;
            vertices[1].Position = new Vector3(min.X, max.Y, min.Z);
            vertices[1].Color = Color.Red;
            vertices[2].Position = new Vector3(max.X, max.Y, min.Z);
            vertices[2].Color = Color.Red;
            vertices[3].Position = new Vector3(max.X, min.Y, min.Z);
            vertices[3].Color = Color.Red;

            vertices[4].Position = new Vector3(min.X, min.Y, max.Z);
            vertices[4].Color = Color.Red;
            vertices[5].Position = new Vector3(min.X, max.Y, max.Z);
            vertices[5].Color = Color.Red;
            vertices[6].Position = max;
            vertices[6].Color = Color.Red;
            vertices[7].Position = new Vector3(max.X, min.Y, max.Z);
            vertices[7].Color = Color.Red;

            indices = new int[24];

            indices[0] = 0;
            indices[1] = 1;
            indices[2] = 2;
            indices[3] = 3;
            indices[4] = 0;
            indices[5] = 3;
            indices[6] = 1;
            indices[7] = 2;

            indices[8] = 4;
            indices[9] = 5;
            indices[10] = 6;
            indices[11] = 7;
            indices[12] = 4;
            indices[13] = 7;
            indices[14] = 5;
            indices[15] = 6;

            indices[16] = 0;
            indices[17] = 4;
            indices[18] = 1;
            indices[19] = 5;
            indices[20] = 2;
            indices[21] = 6;
            indices[22] = 3;
            indices[23] = 7;
            

            //indices[0] = 2;
            //indices[1] = 1;
            //indices[2] = 0;
            //indices[3] = 0;
            //indices[4] = 3;
            //indices[5] = 2;

            //indices[6] = 4;
            //indices[7] = 5;
            //indices[8] = 6;
            //indices[9] = 6;
            //indices[10] = 7;
            //indices[11] = 4;

            //indices[12] = 0;
            //indices[13] = 1;
            //indices[14] = 4;
            //indices[15] = 1;
            //indices[16] = 5;
            //indices[17] = 4;

            //indices[18] = 2;
            //indices[19] = 3;
            //indices[20] = 6;
            //indices[21] = 3;
            //indices[22] = 7;
            //indices[23] = 6;

            //indices[24] = 1;
            //indices[25] = 2;
            //indices[26] = 5;
            //indices[27] = 5;
            //indices[28] = 2;
            //indices[29] = 6;
        }

        
        public void collision(List<Movable> solids)
        {
            BoundingBox Rect = getAABB();
            findCollisions(Rect, solids);
        }

        public void dibugdraw(GraphicsDevice graphics, Matrix View, Matrix Projection, Effect effect)
        {
            SetUpVertices(getAABB());

            effect.CurrentTechnique = effect.Techniques["Pretransformed"];
            effect.Parameters["xView"].SetValue(View);
            effect.Parameters["xProjection"].SetValue(Projection);
            effect.Parameters["xWorld"].SetValue(Matrix.Identity);
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphics.DrawUserIndexedPrimitives(PrimitiveType.LineList, vertices, 0, vertices.Length, indices, 0, indices.Length/2, VertexPositionColor.VertexDeclaration);
            }
        }

        //protected void collision(List<Movable> solids)
        //{
        //    BoundingBox Rect = creatbox();

        //    List<Movable> collosions = FindCollisions(Rect, solids);


        //    handal collosions
        //    for (int i = 0; i < collosions.Count; i++)
        //    {
        //        collosininfo info = getcollisioninfo(Rect, collosions[i]);

        //        if (info.direction == direction.up)
        //        {
        //            Position.Y = OldPosition.Y;
        //            Vellasity.Y *= elasticity;
        //        }
        //        else if (info.direction == direction.down)
        //        {
        //            Position.Y = OldPosition.Y;
        //            Vellasity.Y *= elasticity;
        //        }
        //        else if (info.direction == direction.left)
        //        {
        //            Vellasity.X *= elasticity;
        //            Position.X = OldPosition.X;
        //        }
        //        else if (info.direction == direction.right)
        //        {
        //            Vellasity.X *= elasticity;
        //            Position.X = OldPosition.X;
        //        }
        //    }
        //}

        //protected List<Movable> FindCollisions(BoundingBox a, List<Movable> solids)
        //{
        //    List<Movable> result = new List<Movable>();

        //    foreach (Movable i in solids)
        //    {
        //        if (a.Intersects(i.creatbox()))
        //            result.Add(i);
        //    }
        //    return result;
        //}

        protected void findCollisions(BoundingBox a, List<Movable> solids)
        {
            contact = false;
            foreach (Movable i in solids)
            {
                BoundingBox box = i.getAABB();
                if (a.Intersects(box)){
                    contact = true;
                    collosininfo info = getcollisioninfo(a, box);

                    

                        if (info.direction == direction.forward)
                        {
                         
                            Position.Z -= info.intersection;
                            Vellasity.Z *= elasticity;
                        }
                        else if (info.direction == direction.backward)
                        {
                          
                            Position.Z += info.intersection;
                            Vellasity.Z *= elasticity;
                        }
                        else if (info.direction == direction.left)
                        {
                           
                            Vellasity.X *= elasticity;
                            Position.X += info.intersection;;
                        }
                        else if (info.direction == direction.right)
                        {
                            
                            Vellasity.X *= elasticity;
                            Position.X -= info.intersection;
                        }
                        else if (info.direction == direction.up)
                        {
                            
                            Vellasity.Y *= elasticity;
                            Position.Y += info.intersection; 
                        }
                        else if (info.direction == direction.down)
                        {
                            
                            Vellasity.Y *= elasticity;
                            Position.Y -= info.intersection;
                        }
                        else if (info.direction == direction.other)
                        {

                            
                        }
                    

                    return;
                }
             }
        }

        protected collosininfo getcollisioninfo(BoundingBox a, BoundingBox b)
        {
            direction rusult;//ouhpuh value 
            float intersectien;//output value 
            bool x = new bool();//colison direction on x-axis
            bool y = new bool();//colison direction on y-axis
            bool z = new bool();//colison direction on z-axis
            float xintersect = new float();
            float yintersect = new float();
            float zintersect = new float();
            

            Vector3 amin = a.Min;
            Vector3 amax = a.Max;
            Vector3 bmin = b.Min;
            Vector3 bmax = b.Max;

            //colculate intersectinon along x axis
            if (amin.X < bmax.X &&
                amin.X > bmin.X)
            {
                x = true;
                xintersect = bmax.X -amin.X;
            }
            else
            if (amax.X < bmax.X &&
                amax.X > bmin.X)
            {
                x = false;
                xintersect = amax.X - bmin.X;

            }
            //colculate intersectinon along y axis
            if (amin.Y < bmax.Y &&
                amin.Y > bmin.Y)
            {
                y = true;
                yintersect = bmax.Y - amin.Y;
            }
            else
            if (amax.Y < bmax.Y &&
                amax.Y > bmin.Y)
            {
                y = false;
                yintersect = amax.Y - bmin.Y;

            }
            //colculate intersectinon along z axis
            if (amin.Z < bmax.Z &&
                amin.Z > bmin.Z)
            {
                z = true;
                zintersect = bmax.Z - amin.Z;
            }
            else
            if (amax.Z < bmax.Z &&
                amax.Z > bmin.Z)
            {
                z = false;
                zintersect = amax.Z - bmin.Z;

            }



            //deturmin direction
            if (xintersect < zintersect&&
                xintersect < yintersect)
            {

                intersectien = xintersect;
                if (x)
                {
                    rusult = direction.left;

                }
                else
                {
                    rusult = direction.right;

                }

            }
            else
            if (zintersect < xintersect&&
                zintersect < yintersect)
            {
                intersectien = zintersect;
                if (z)
                {
                    rusult = direction.backward;

                }
                else
                {
                    rusult = direction.forward;

                }
            }
            else
            if(yintersect < xintersect&&
               yintersect < zintersect){

                intersectien = yintersect;
                if (y)
                {
                    rusult = direction.up;

                }
                else
                {
                    rusult = direction.down;

                }
            }
            else
            {
                rusult = direction.other;
                intersectien = 0;
            }
            
            
            return new collosininfo(rusult, intersectien);
        }

        

        //protected collosininfo getcollisioninfo(Rectangle a, Rectangle b)
        //{

        //    if ((a.Left > b.Left && a.Right < b.Right) ||
        //        (a.Left < b.Left && a.Right > b.Right))
        //    {


        //        if (a.Top < b.Bottom)
        //        {

        //            ////////////////////////////////////////////////
        //            ///////The hero hits the object from below//////
        //            ////////////////////////////////////////////////
        //            OutPut.Out("below");

        //        }
        //        else
        //        if (a.Bottom > b.Top)
        //        {
        //            ////////////////////////////////////////////////
        //            ///////The hero hits the object from above//////
        //            ////////////////////////////////////////////////
        //            OutPut.Out("above");
        //        }

        //    }
        //    else
        //        if ((a.Top < b.Top && a.Bottom > b.Bottom) ||
        //           (a.Top > b.Top && a.Bottom < b.Bottom))
        //        {

        //            if (a.Left < b.Right)
        //            {
        //                ////////////////////////////////////////////////
        //                ///////The hero hits the object from left///////
        //                ////////////////////////////////////////////////
        //                OutPut.Out("left");


        //            }
        //            else
        //            if (a.Right > b.Left)
        //            {
        //                ////////////////////////////////////////////////
        //                ///////The hero hits the object from right//////
        //                ////////////////////////////////////////////////
        //                OutPut.Out("right");

        //            }
        //        }
        //    return new collosininfo(new direction(), new float());
        //}
    }

